/*
 * UNPUBLISHED SOURCE CODE
 *
 * Copyright 2007, 2008, MaxiScale, Inc.
 * ALL RIGHTS RESERVED.
 *
 * MAXISCALE HIGHLY CONFIDENTIAL TRADE SECRET INFORMATION
 *
 * Access or possession of this material grants you no right or license,
 * express, implied, statutory or otherwise, under any MaxiScale patent,
 * copyright, trade secret right or other intellectual property right.
 * Any such license must be contained in a written license agreement
 * signed by an authorized officer of MaxiScale.  Additionally, access or
 * possession of this material is limited to MaxiScale employees with a
 * need to know or named employees of MaxiScale vendors authorized by
 * MaxiScale in writing to access this material.
 *
 * Restricted Rights: Use, duplication, or disclosure by the U.S.
 * Government is subject to restrictions of FAR 52.227-19 and its
 * successors, or (c)(1)(ii) of the Rights in Technical Data and
 * Computer Software clause at DFAR 252.227-7013 and its successors.
 *
 * MaxiScale, Inc.
 */

/*
 * This file contains ...
 *
 * Date:        $Date$
 * Revision:    $Rev$
 * Author:      $Author$
 * HeadURL:     $HeadURL$
 * File Id:     $Id$
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include <sys/xattr.h>

#include "sfr.h"
#include "sfr_user.h"

#define IS_SLASH(c) (c == '/')

static char *
strip_slashes(char *path, int slashes)
{
	char *t;
	int left;
	int incl_slash;

	if (slashes == 0)
		return path;
	if (slashes < 0) {
		left = -slashes;
		incl_slash = 1;
	} else {
		left = slashes;
		incl_slash = 0;
	}
	for (t = path; *t; t++) {
		if (IS_SLASH(*t)) {
			while (IS_SLASH(*(t+1)))
				t++;
			if (--left <= 0)
				return incl_slash ? t : (t+1);
		}
	}
	return (char *) NULL;
}


static ssize_t
_SFR_sys_store(const char *mnt, const struct iovec *vector, int count,
	       off_t offset, off_t prefill, const char *suffix,
	       mode_t mode, char *result)
{
	struct sfn sfn;
	int rv = 0;

	memset(&sfn, 0, sizeof(struct sfn));

	sfn.version = 0;

	sfn.vector = vector;
	sfn.count = count;

	sfn.offset = offset;
	sfn.prefill = prefill;

	sfn.suffix = suffix;
	sfn.result = result;
	sfn.mode = mode;

	if ((rv = setxattr(mnt, "/xfr", &sfn, sizeof(sfn), 0)))
		return (ssize_t) rv;

	rv = 0;
	while (count--) {
		rv += (int) vector->iov_len;
		vector++;
	}
	return (ssize_t) rv;
}


ssize_t
SFR_Write_Path(const char *mnt, const struct iovec *vector, int count,
	       off_t offset, off_t prefill, const char *suffix,
	       char *path, int pathlen)
{
	// SFR_FID_LEN is the length of the FID key (without '\0')
	// SFR_SUFFIX_MAX includes space for a null-terminator
	char pathbuf[SFR_FID_LEN + SFR_SUFFIX_MAX + 40];
	char *base;
	ssize_t rv;

	rv = _SFR_sys_store(mnt, vector, count, offset, prefill,
			    suffix, 00444, pathbuf);
	if (rv < 0)
		return rv;

	if (!(base = strip_slashes(pathbuf, -2)))
		base = pathbuf;

	strncpy(path, base, pathlen);
	return rv;
}

char *
SFR_Write(const char *mnt, const char *buf, int len, const char *suffix)
{
	struct iovec iov;
	char *res;

	// SFR_FID_LEN is the length of the FID key (without '\0')
	// SFR_SUFFIX_MAX includes space for a null-terminator
	res = (char *) malloc(SFR_FID_LEN + SFR_SUFFIX_MAX);
	if (!res) {
		errno = ENOMEM;
		return NULL;
	}

	iov.iov_base = (void *) buf;
	iov.iov_len = len;

	if (SFR_Write_Path(mnt, &iov, 1, 0, len, suffix, res,
			   SFR_FID_LEN + SFR_SUFFIX_MAX) < 0) {
		free(res);
		return NULL;
	}

	return res;
}

ssize_t
SFR_Write_2(const char *mnt, const char *buf, int len, const char *suffix, char **path)
{
	struct iovec iov;
	char *pathret;
	ssize_t res;

	// SFR_FID_LEN is the length of the FID key (without '\0')
	// SFR_SUFFIX_MAX includes space for a null-terminator
	pathret = (char *) malloc(SFR_FID_LEN + SFR_SUFFIX_MAX);
	if (!pathret) {
		errno = ENOMEM;
		return -1;
	}

	iov.iov_base = (void *) buf;
	iov.iov_len = len;

	if ((res = SFR_Write_Path(mnt, &iov, 1, 0, len, suffix, pathret,
				  SFR_FID_LEN + SFR_SUFFIX_MAX)) < 0) {
		free(pathret);
		return -1;
	}

	*path = pathret;
	return res;
}

ssize_t
SFR_Write_3(const char *mnt, const struct iovec *vector, int count, int prefill, const char *suffix, char **path)
{
	// SFR_FID_LEN is the length of the FID key (without '\0')
	// SFR_SUFFIX_MAX includes space for a null-terminator
	char *pathret = (char *) malloc(SFR_FID_LEN + SFR_SUFFIX_MAX);
	ssize_t res;

	if (!pathret) {
		errno = ENOMEM;
		return -1;
	}

	if ((res = SFR_Write_Path(mnt, vector, count, 0, prefill, suffix, pathret,
				  SFR_FID_LEN + SFR_SUFFIX_MAX)) < 0) {
		free(pathret);
		return -1;
	}

	*path = pathret;
	return res;
}
